package network.ssl.image;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import ucp.projects.kraken.kamcenter.plugin.CameraFrame;

import network.ssl.KrakenSSLServer;

public class KrakenImageThreadServer implements Runnable {

	private final int DEFAULT_PORT_NUMBER = 18002;
	
	private KrakenSSLServer krakenSSLServer;
	private Thread thread;
	private ArrayList<PrintWriter> tabClients;
	private ConcurrentHashMap<String, CameraFrame> framesMap;
	private int nbClients;
	private int port;
	private boolean serverOn;
	
	final Lock lock = new ReentrantLock();
	final Condition turn = lock.newCondition();

	public KrakenImageThreadServer(KrakenSSLServer krakenSSLServer, String port_){
		try{
			this.krakenSSLServer = krakenSSLServer;
			tabClients = new ArrayList<PrintWriter>(); // contiendra tous les flux de sortie vers les clients
			framesMap = new ConcurrentHashMap<String, CameraFrame>();
			nbClients = 0;
			serverOn = true;
			
			if(port_.equals(""))	port = DEFAULT_PORT_NUMBER; //port 18000 par défaut
			else	port = new Integer(port_); //sinon premier argument
	    }
	    catch(Exception e){
	    	e.printStackTrace();//
	    }
		thread = new Thread(this);
		thread.start();
	}
	
	public void run() {
		try {
			ServerSocket serverSocket = new ServerSocket(port);
			printWelcome(port);
			
		    while(serverOn){ // attente en boucle de connexion (bloquant sur serverSocket.accept)
		    	//new ARTThread(serverSocket.accept(),this); // un client se connecte, un nouveau thread client est lancé
		    	new KrakenImageThread(serverSocket.accept(), this);
		    }
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Informations sur le serveur.
	 * @param port
	 */
	public void printWelcome(Integer port){
		System.out.println("--------");
		System.out.println("Kr4ken Image");
		System.out.println("Projet Kr4ken M2 ISIM SIC 2014");
		System.out.println("Version 0.2 : 19/05/2014");
		System.out.println("--------");
		System.out.println("Demarre sur le port : " +port.toString());
		System.out.println("--------");
	}

	/**
	 * Envoi un message à tous les clients du serveur.
	 * @param message
	 * @param sLast
	 */
	synchronized public void sendAll(String message,String sLast){
		PrintWriter out;
		
		for(int i = 0; i < tabClients.size(); i++){ 
			out = (PrintWriter) tabClients.get(i);
			
			if(out != null){
				out.println(message+sLast);
				out.flush();
			}
		}
	}
	
	/**
	 * Envoi un message au client precise du serveur.
	 * @param message
	 * @param sLast
	 */
	synchronized public void sendToComm(PrintWriter comm_out, String message,String sLast){
		PrintWriter out = comm_out;
		
		//for(int i = 0; i < tabClients.size(); i++){ 
		//	out = (PrintWriter) tabClients.get(i);
			
			if(out != null){
				out.println(message+sLast);
				out.flush();
				System.out.println("cmd envoyeeToComm:"+message);
			}
			else{
				System.out.println("cmd envoyeeToComm impossible, PrintWriter null");
			}
		//}
	}
	
	/**
	 * Envoi un message au client precise du serveur.
	 * @param message
	 * @param sLast
	 */
	synchronized public void sendToClientForVideo(PrintWriter comm_out, String message,String sLast){
		PrintWriter out = comm_out;
		
		//for(int i = 0; i < tabClients.size(); i++){ 
		//	out = (PrintWriter) tabClients.get(i);
			
			if(out != null){
				out.println(message+sLast);
				out.flush();
				System.out.println("cmd envoyeeToComm:"+message);
			}
			else{
				System.out.println("cmd envoyeeToComm impossible, PrintWriter null");
			}
		//}
	}
	
	public int getPort(){ return this.port; }
	
	public void setServerOnOff(boolean state){ this.serverOn = state; }

	/**
	 * Ajout un nouveau client.
	 * @param out
	 * @return
	 */
	synchronized public int addClient(PrintWriter out){
		nbClients++;
		tabClients.add(out);
		return tabClients.size()-1;
	}
	
	/**
	 * Supprime le client.
	 * @param i
	 */
	synchronized public void delClient(int i){
		nbClients--;
		
		if(tabClients.get(i) != null){
			tabClients.remove(i);
		}
	}

	/**
	 * Le nombre de clients connectés.
	 * @return
	 */
	synchronized public int getNbClients(){
		return nbClients;
	}

	public KrakenSSLServer getKrakenSSLServer() {	return krakenSSLServer;	}
	public void setKrakenSSLServer(KrakenSSLServer krakenSSLServer) {	this.krakenSSLServer = krakenSSLServer;	}

	public ConcurrentHashMap<String, CameraFrame> getFramesMap() {	return framesMap;	}
	//public void setFramesMap(ConcurrentHashMap<String, CameraFrame> framesMap) {	this.framesMap = framesMap;	}
	
	public void insertFrameIntoMap(String sourceName, CameraFrame frame){
		this.framesMap.put(sourceName, frame);
		//System.out.println("InsertImageFrom:"+sourceName);
	}
	

}
